package com.example.nacosdemo;

/**
 * Nacos Demo 应用主类
 *
 * @author ZRS
 * @version V1.0
 */

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;

import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

// 使用proxyBeanMethods=false优化启动性能
@SpringBootApplication(proxyBeanMethods = false)
public class NacosDemoApplication {

    private static final Logger logger = LoggerFactory.getLogger(NacosDemoApplication.class);

    public static void main(String[] args) {
        try {
            // 1. 预配置：添加必要的系统属性，确保Nacos客户端行为可控
            System.setProperty("spring.cloud.bootstrap.enabled", "true");
            System.setProperty("com.alibaba.nacos.client.naming.tls.enable", "false");
            
            // 2. 启动前检查Nacos服务是否可访问
            boolean nacosReachable = checkNacosConnection();
            
            // 3. 创建Spring应用构建器
            SpringApplicationBuilder builder = new SpringApplicationBuilder(NacosDemoApplication.class);
            
            // 4. 如果Nacos不可达，添加覆盖配置确保应用能启动
            if (!nacosReachable) {
                logger.warn("Nacos服务器不可达，启用降级配置模式");
                Map<String, Object> overrideProperties = new HashMap<>();
                overrideProperties.put("spring.cloud.nacos.config.enabled", false);
                overrideProperties.put("spring.cloud.nacos.discovery.enabled", false);
                builder.properties(overrideProperties);
            }
            
            // 5. 启动应用，捕获任何初始化异常
            ConfigurableApplicationContext context = builder.run(args);
            
            // 6. 应用启动成功后的处理
            onApplicationStarted(context);
            
        } catch (Exception e) {
            // 7. 捕获并处理所有启动异常，确保提供有用的诊断信息
            handleStartupException(e);
        }
    }
    
    /**
     * 应用启动成功后的处理
     */
    private static void onApplicationStarted(ConfigurableApplicationContext context) {
        ConfigurableEnvironment env = context.getEnvironment();
        String serviceName = env.getProperty("spring.application.name", "nacos-demo-service");
        String serverPort = env.getProperty("server.port", "8080");
        
        logger.info("===========================================");
        logger.info("应用 [{}] 启动成功！", serviceName);
        logger.info("服务运行端口: {}", serverPort);
        logger.info("健康检查端点: http://localhost:{}/actuator/health", serverPort);
        logger.info("注意：应用配置了容错机制，即使Nacos连接失败也能启动");
        logger.info("===========================================");
    }
    
    /**
     * 处理启动异常
     */
    private static void handleStartupException(Exception e) {
        logger.error("应用启动过程中发生异常:", e);
        
        // 针对特定异常类型提供更具体的诊断信息
        if (e.getMessage() != null && e.getMessage().contains("NacosConnectionFailureException")) {
            logger.error("Nacos连接失败，可能的原因:");
            logger.error("1. Nacos服务器未启动或不可达");
            logger.error("2. 网络连接问题或防火墙限制");
            logger.error("3. 配置的Nacos服务器地址不正确");
            logger.error("4. Nacos服务端口未开放");
            logger.error("请确保Nacos服务器已正确运行，并且地址配置正确");
        }
        
        // 输出系统环境信息用于诊断
        logger.info("环境变量 NACOS_SERVER_ADDR: {}", System.getenv("NACOS_SERVER_ADDR"));
        logger.info("环境变量 NACOS_USERNAME: {}", System.getenv("NACOS_USERNAME"));
    }
    
    /**
     * 检查Nacos服务器连接状态
     * @return 是否可达
     */
    private static boolean checkNacosConnection() {
        String nacosServer = System.getenv("NACOS_SERVER_ADDR");
        if (nacosServer == null) {
            nacosServer = "localhost:8848";
        }
        
        String[] parts = nacosServer.split(":");
        String host = parts[0];
        int port = parts.length > 1 ? Integer.parseInt(parts[1]) : 8848;
        
        try (Socket socket = new Socket()) {
            socket.connect(new java.net.InetSocketAddress(host, port), 3000);
            logger.info("Nacos服务器 [{}:{}] 网络连接正常", host, port);
            return true;
        } catch (IOException e) {
            logger.warn("警告：无法连接到Nacos服务器 [{}:{}]，原因：{}", host, port, e.getMessage());
            logger.warn("应用将尝试使用容错模式启动，请确保Nacos服务器已正确配置并运行");
            return false;
        }
    }

}